﻿namespace Jsl.StyleCop.CSharp.RefactoringRules
{
    using Microsoft.VisualStudio.TestTools.UnitTesting;

    [TestClass]
    public class TestLocalVariableSettingUnused : TestBase<RuleAnalyzer>
    {
        #region Constructors
        /// <summary>
        /// Initializes a new instance of the <see cref="TestLocalVariableSettingUnused"/> class.
        /// </summary>
        public TestLocalVariableSettingUnused()
            : base(RuleAnalyzer.LocalVariableAssignmentUnused)
        {
        }
        #endregion Constructors

        [TestMethod]
        public void No_variables_is_OK()
        {
            this.TestMethod(
@"public int Method()
{
    return 5;
}");
        }

        [TestMethod]
        public void Setting_fields_is_ignored()
        {
            this.TestMethod(
@"public int Method()
{
    field = 5;
    return 6;
}");
        }

        [TestMethod]
        public void Parameters_are_processed_too()
        {
            this.TestMethod(
@"public int Method(int parameter)
{
    parameter = 5;
}",
                new ViolationInfo(3, "The variable 'parameter' assignment isn't used or is overwritten before it is used."));
        }

        [TestMethod]
        public void Used_variable_setting_is_OK()
        {
            this.TestMethod(
@"public int Method()
{
    int variable = 5;
    return variable;
}");
        }

        [TestMethod]
        public void Unused_setting_is_a_problem()
        {
            this.TestMethod(
@"public int Method()
{
    int variable = 5;
    return 7;
}",
                new ViolationInfo(3, "The variable 'variable' assignment isn't used or is overwritten before it is used."));
        }

        [TestMethod]
        public void Variable_value_is_overwritten_before_use()
        {
            this.TestMethod(
@"public int Method()
{
    int variable = 5;
    variable = 6;
    return variable;
}",
                new ViolationInfo(3, "The variable 'variable' assignment isn't used or is overwritten before it is used."));
        }

        [TestMethod]
        public void Variable_value_is_overwritten_in_IF_is_OK()
        {
            this.TestMethod(
@"public int Method()
{
    int variable = 5;
    if (true)
    {
        variable = 6;
    }

    return variable;
}");
        }

        [TestMethod]
        public void Variable_value_is_overwritten_in_out_parameter()
        {
            this.TestMethod(
@"public int Method()
{
    int variable = 5;
    var dictionary = new Dictionary<string, int>();
    if (dictionary.TryGetValue(""XXX"", out variable))
    {
    }

    return variable;
}",
                new ViolationInfo(3, "The variable 'variable' assignment isn't used or is overwritten before it is used."));
        }

        [TestMethod]
        public void Variable_only_used_as_an_out_parameter_is_OK()
        {
            this.TestMethod(
@"public int Method()
{
    int variable;
    if (dictionary.TryGetValue(""XXX"", out variable))
    {
    }
}");
        }

        [TestMethod]
        public void Out_parameters_are_counted_as_used()
        {
            this.TestMethod(
@"public void Method(out bool parameter)
{
    parameter = true;
}");
        }

        [TestMethod]
        public void Ref_parameters_are_counted_as_used()
        {
            this.TestMethod(
@"public void Method(ref bool parameter)
{
    parameter = true;
}");
        }

        [TestMethod]
        public void Variable_only_used_as_an_ref_parameter_is_OK()
        {
            this.TestMethod(
@"public int Method()
{
    int variable;
    if (dictionary.TryGetValue(""XXX"", ref variable))
    {
    }
}");
        }

        [TestMethod]
        public void Catch_variables_are_OK()
        {
            this.TestMethod(
@"public Exception Method()
{
    try
    {
    }
    catch (Exception ex)
    {
        return ex;
    }
}");
        }

        [TestMethod]
        public void Catch_variables_are_checked()
        {
            this.TestMethod(
@"public Exception Method()
{
    try
    {
    }
    catch (Exception ex)
    {
        ex = null;
        throw ex;
    }
}",
                new ViolationInfo(6, "The variable 'ex' assignment isn't used or is overwritten before it is used."));
        }

        [TestMethod]
        public void Increment_counts_as_a_usage_followed_by_an_assignment()
        {
            this.TestMethod(
@"public int Method()
{
    int variable = 12;
    variable += 1;
    return variable;
}");
        }

        [TestMethod]
        public void Variables_in_lambdas_are_processed()
        {
            this.TestMethod(
@"public void Method()
{
    Method(() => { int variable = 1; });
}",
                new ViolationInfo(3, "The variable 'variable' assignment isn't used or is overwritten before it is used."));
        }

        [TestMethod]
        public void Variables_in_anonymous_methods_are_processed()
        {
            this.TestMethod(
@"public void Method()
{
    Method(delegate()
        {
            int variable = 1;
        });
}",
                new ViolationInfo(5, "The variable 'variable' assignment isn't used or is overwritten before it is used."));
        }
    }
}